/*************************************************************************//**
 *****************************************************************************
 * @file   misc.c
 * @brief  
 * @author Forrest Y. Yu
 * @date   2008
 *****************************************************************************
 *****************************************************************************/

/* Orange'S FS */
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
#include "hd.h"
#include "fs.h"

/*****************************************************************************
 *                                search_file
 *****************************************************************************/
/**
* 搜索文件并返回 inode_nr。
  *
  * @param[in] path 要搜索的文件的完整路径。
  * @return Ptr 如果成功，则返回文件的 i 节点，否则为零。
 * 
 * @see open()
 * @see do_open()
 *****************************************************************************/
PUBLIC int search_file(char * path)
{
	int i, j;

	char filename[MAX_PATH];
	memset(filename, 0, MAX_FILENAME_LEN);
	struct inode * dir_inode;
	if (strip_path(filename, path, &dir_inode) != 0)
		return 0;

	if (filename[0] == 0)	/* path: "/" */
		return dir_inode->i_num;

	/**
	 * 在目录中搜索文件。
	 */
	int dir_blk0_nr = dir_inode->i_start_sect;
	int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
	int nr_dir_entries =
	  dir_inode->i_size / DIR_ENTRY_SIZE; // 包括未使用的插槽（文件已被删除但插槽仍然存在）
	int m = 0;
	struct dir_entry * pde;
	for (i = 0; i < nr_dir_blks; i++) {
		RD_SECT(dir_inode->i_dev, dir_blk0_nr + i);
		pde = (struct dir_entry *)fsbuf;
		for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) {
			if (memcmp(filename, pde->name, MAX_FILENAME_LEN) == 0)
				return pde->inode_nr;
			if (++m > nr_dir_entries)
				break;
		}
		if (m > nr_dir_entries) /* 所有条目都已迭代 */
			break;
	}

	/* file not found */
	return 0;
}

/*****************************************************************************
 *                                strip_path
 *****************************************************************************/
/**
* 从完整路径中获取基本名称。
  *
  * 在Orange'S FS v1.0 中，所有文件都存放在根目录下。
  * 没有子文件夹的东西。
  *
  * 此例程应在文件操作的最开始调用
  * 例如 open()、read() 和 write()。 它接受完整路径并返回
  * 两件事：根目录的 i 节点的基本名称和 ptr。
  *
  * 例如 在 stip_path(filename, "/blah", ppinode) 完成后，我们得到：
  * - 文件名：“废话”
  * - *ppinode: root_inode
  * - ret val：0（成功）
  *
  * 目前可接受的路径名最多应以一个 `/' 开头
  * 在文件名之前。
  *
  * 文件名可以包含除 '/' 和 '\\0' 之外的任何字符。
 *
* @param[out] filename 结果的字符串。
  * @param[in] pathname 完整的路径名。
  * @param[out] ppinode dir 的 inode 的 ptr 将存储在这里。
 * 
 * @return 如果成功则为零，否则路径名无效。
 *****************************************************************************/
PUBLIC int strip_path(char * filename, const char * pathname,
		      struct inode** ppinode)
{
	const char * s = pathname;
	char * t = filename;

	if (s == 0)
		return -1;

	if (*s == '/')
		s++;

	while (*s) {		/* 检查每个字符 */
		if (*s == '/')
			return -1;
		*t++ = *s++;
		/* 如果文件名太长，则截断它 */
		if (t - filename >= MAX_FILENAME_LEN)
			break;
	}
	*t = 0;

	*ppinode = root_inode;

	return 0;
}

